﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Web;
using System.Reflection;
using System.Diagnostics;
using System.Collections;
using System.Data.SqlClient;
using System.Configuration;
using Enterprise.Exceptions;
using System.Xml;

namespace Enterprise.Modules
{
    /// <summary>
    /// Loads Modules independent of there type.
    /// </summary>
    public class ModuleLoader
    {
        private static ModuleLoader _instance;

        private ModuleLoader() { }

        /// <summary>
        /// Creates an instance of ModuleLoader
        /// </summary>
        /// <returns>Instance of ModulLoader</returns>
        public static ModuleLoader GetInstance()
        {
            if (_instance == null)
                _instance = new ModuleLoader();
            return _instance;
        }


        /// <summary>
        /// Creates an instance of any type of class from the given id.
        /// </summary>
        /// <param name="id">The Module's id to create an instance of.</param>
        /// <returns>Instance of Module created</returns>
        public IModule LoadModule(string id)
        {
            string filename = getAssemblyType(id);

            Type[] typesInAssembly = LoadAssembly(string.Format("Enterprise.{0}", filename)).GetExportedTypes();

            foreach (Type type in typesInAssembly)
            {
                if (type.IsClass && type.Name == filename)
                    return (IModule)Activator.CreateInstance(type, new object[] { id });
            }

            return null;
        }


        /// <summary>
        /// Loads the specified assembly
        /// </summary>
        /// <param name="assemblyName">The assembly to load</param>
        /// <returns>Loaded assembly</returns>
        private Assembly LoadAssembly(string assemblyName)
        {
            string s = string.Empty;
            Assembly[] dll = AppDomain.CurrentDomain.GetAssemblies();
            foreach (Assembly a in dll)
            {
                string[] nameArr = a.GetName().ToString().Split(',');
                string name = nameArr[0];



                if (name.Contains(assemblyName))
                {
                    return Assembly.Load(name);
                }
            }
            
            return null;
        }


        /// <summary>
        /// Reads from xml and returns ClassName 
        /// </summary>
        /// <param name="id">ID of the module to get type from</param>
        /// <returns>ClassName from XML</returns>
        private string getAssemblyType(string id)
        {
            SqlConnection Conn = new SqlConnection(Config.ConnectionString());
            try
            {
                //  object o = HttpContext.Current.Cache["TYPE" + id];
                //  o = null;
                //  if (o == null)
                //  {
                
                SqlCommand command = new SqlCommand(string.Format("SELECT ObjectData FROM Objects WHERE id={0}", id), Conn);
                Conn.Open();
                SqlDataReader dr = command.ExecuteReader();
                if (dr.Read())
                {
                    XmlDocument xml = new XmlDocument();
                    xml.LoadXml(Convert.ToString(dr["ObjectData"]));
                    return xml.SelectSingleNode("//ClassName").InnerText;

                    //HttpContext.Current.Cache.Insert("TYPE"+id, string.Format("Enterprise.Modules.{0}", xml.SelectSingleNode("//ClassName").InnerText));
                }
                return null;
                //}
            }
            catch (Exception ec) { throw ec; }
            finally
            {
                Conn.Close();
            }
            //return (string)HttpContext.Current.Cache["TYPE" + id];
        }
    }
}
